package bb.lanxing.activity.bluetooth

import android.annotation.SuppressLint
import android.app.ProgressDialog
import android.content.BroadcastReceiver
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.os.Bundle
import android.os.CountDownTimer
import android.os.Environment
import android.util.Log
import android.view.View
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.lifecycleScope
import bb.lanxing.R
import bb.lanxing.activity.base.BaseDisplayActivity
import bb.lanxing.calc.data.DisplayPoint
import bb.lanxing.databinding.ActivityHeartRate01StatusBinding
import bb.lanxing.devices.utils.XZDeviceHelper
import bb.lanxing.lib.devices.api.ConnectionListener
import bb.lanxing.lib.devices.api.DeviceManager
import bb.lanxing.lib.devices.api.SmartDevice
import bb.lanxing.lib.devices.base.DeviceContext
import bb.lanxing.lib.devices.ble.BleCons
import bb.lanxing.lib.devices.ble.device.HeartRate01Device
import bb.lanxing.lib.devices.ble.dfu.DfuContext
import bb.lanxing.lib.devices.ble.dfu.IDfuProgressCallback
import bb.lanxing.lib.devices.core.utils.DeviceHelper
import bb.lanxing.lib.devices.utils.DeviceVersionHelper
import bb.lanxing.model.database.Device
import bb.lanxing.network.BiCiCallback
import bb.lanxing.network.MyHttpClient
import bb.lanxing.util.FileDownloadUtils
import bb.lanxing.view.BiciAlertDialogBuilder
import gov.nist.core.Separators
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.json.JSONObject
import java.io.File
import java.util.Objects

class HeartRate01StatusActivity : BaseDisplayActivity(), ConnectionListener, IDfuProgressCallback {


    private var device: Device? = null
    private var switchModeTimer: CountDownTimer? = null
    private var mDfuContext: DfuContext? = null
    private var mDfuProgressDialog: ProgressDialog? = null
    private var currentMode = 0
    private var isShowFailToast = true

    private lateinit var binding: ActivityHeartRate01StatusBinding
    private var dfuFilePath: String = ""
    private var downloadUrl: String? = ""
    private var verName: String? = ""
    private var isChecking = false

    private val broadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            val action = intent.action
            Log.d(TAG, "$javaClass onReceive action = $action")
            when (Objects.requireNonNull(action)) {
                BleCons.ACTION_DEVICE_INFORMATION -> {
                    if (intent.getIntExtra(
                            "EXTRA_DEVICE_TYPE", 0
                        ) != SmartDevice.TYPE_HEART_RATE01
                    ) {
                        return
                    }
                    val stringExtra = intent.getStringExtra("EXTRA_DEVICE_INFORMATION")
                    if (stringExtra != null) {
                        setUIVersion(stringExtra)
                        DeviceContext.saveDeviceVersion(device!!.address, stringExtra)
                    }
                    val stringExtra2 = intent.getStringExtra("EXTRA_MODEL")
                    if (stringExtra2 != null) {
                        setUIModel(stringExtra2)
                        if (device != null) {
                            DeviceVersionHelper.setModelVersion(
                                context, device!!.address, stringExtra2
                            )
                        }
                    }
                    val stringExtra3 = intent.getStringExtra("EXTRA_EXTRA_MANUFACTURE")
                    if (stringExtra3 != null) {
                        setUIManufacture(stringExtra3)
                    }
                }

                BleCons.ACTION_READ_DEVICE_INFORMATION_RESULT -> {
                    val stringExtra4 = intent.getStringExtra(BleCons.EXTRA_MANUFACTURE)
                    val stringExtra5 = intent.getStringExtra(BleCons.EXTRA_FIRMWARE_VERSION)
                    val stringExtra6 = intent.getStringExtra(BleCons.EXTRA_MODEL)
                    val intExtra = intent.getIntExtra(BleCons.EXTRA_BATTERY, 0)
                    if (stringExtra4 == null || stringExtra5 == null || stringExtra6 == null || stringExtra4.isEmpty() || stringExtra5.isEmpty() || stringExtra6.isEmpty()) {
                        requestDeviceInfo()
                    }
                    if (intExtra == 0) {
                        requestBattery()
                    } else {
                        setUIBattery(intExtra)
                    }
                    if (stringExtra4 != null) {
                        setUIManufacture(stringExtra4)
                    }
                    if (stringExtra5 != null) {
                        setUIVersion(stringExtra5)
                    }
                    if (stringExtra6 != null) {
                        setUIModel(stringExtra6)
                    }
                }

                BleCons.ACTION_BATTERY -> {
                    if (intent.getIntExtra(
                            BleCons.EXTRA_DEVICE_TYPE, 0
                        ) == SmartDevice.TYPE_HEART_RATE01
                    ) {
                        setUIBattery(intent.getIntExtra(BleCons.EXTRA_BATTERY, 0))
                    }
                }

                HeartRate01Device.ACTION_DEVICE_MODE_INFO -> {
                    val mode = intent.getIntExtra(HeartRate01Device.EXTRA_HEART_RATE_MODE, 0)
                    setUIMode(mode)
                }

                else -> {}
            }
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
    override fun onCreate(bundle: Bundle?) {
        super.onCreate(bundle)
        binding = ActivityHeartRate01StatusBinding.inflate(layoutInflater)

        setContentView(binding.root)
        bindView()
        setupActionBar(true)
        DeviceHelper.registerConnectionStateListener(this)
        registerReceiver()
        val byAddress = Device.getByAddress(
            intent.getStringExtra(BleCons.EXTRA_DEVICE_ADDRESS)
        )
        device = byAddress

        if (byAddress == null) {
            finish()
            return
        }

        binding.unbindBtn.setOnClickListener { unBoundDeviceConfirm() }
        if (!device?.deviceFwDisplayVersion.isNullOrEmpty()) {
            checkVersion(device?.deviceFwDisplayVersion)
        }
        binding.modeSelect.setOnClickListener {
            val intent = Intent(this, HeartRateModeActivity::class.java)
            intent.putExtra(HeartRate01Device.EXTRA_HEART_RATE_MODE, currentMode)
            startActivity(intent)
        }
        binding.warningSetting.setOnClickListener {
            startActivity(
                Intent(
                    this, HeartRate01SettingActivity::class.java
                )
            )
        }
    }

    @SuppressLint("SetTextI18n")
    override fun onResume() {
        super.onResume()
        if (device != null) {
            if (XZDeviceHelper.isConnected(SmartDevice.TYPE_HEART_RATE01) || XZDeviceHelper.isConnecting(
                    device!!.address
                )
            ) {
                requestMode()
                requestBattery()
                readDeviceInfo()
            } else {
                XZDeviceHelper.connect(device)
            }
        }
    }

    fun unBoundDeviceConfirm() {
        BiciAlertDialogBuilder(this).setTitle(R.string.st_forget_sensor)
            .setMessage(R.string.st_are_you_sure_unbind).setPositiveButton(
                R.string.mine_profile_dialog_btn_unbind
            ) { _: DialogInterface?, i: Int ->
                if (device!!.deviceNumber > 0) {
                    MyHttpClient.deleteDevice(device!!.deviceNumber)
                }
                isShowFailToast = false
                DeviceContext.getDeviceProvider().removeByTypeAndFlag(device!!.type, device!!.flags)
                DeviceContext.getDeviceManager().disconnect(device!!.address)
                DeviceContext.startAndRefreshAutoConnector()
                finish()
            }.setNegativeButton(
                R.string.str_sync_cancel
            ) { _: DialogInterface?, i: Int -> }.show().setCanceledOnTouchOutside(true)
    }

    fun setUIMode(mode: Int) {
        currentMode = mode;
        when (mode) {
            0 -> {
                binding.modeSelect.text = getString(R.string.device_heart_rate01_common_mode)
            }

            1 -> {
                binding.modeSelect.text = getString(R.string.device_heart_rate01_rider_mode)
            }

            2 -> {
                binding.modeSelect.text = getString(R.string.device_heart_rate01_walk_mode)
            }

            3 -> {
                binding.modeSelect.text = getString(R.string.device_heart_rate01_fitness_mode)
            }
        }
    }


    public override fun onStop() {
        super.onStop()
        dismissLoadingDialog()
        val countDownTimer = this.switchModeTimer
        countDownTimer?.cancel()
    }

    private fun requestMode() {
        val device = this.device
        if (device == null || device.address == null) {
            return
        }

        binding.batteryView.postDelayed({
            if (XZDeviceHelper.getHeartRate01Controller() != null) {
                XZDeviceHelper.getHeartRate01Controller().readCurrentMode()
            }
        }, 1300L)
    }

    fun requestBattery() {
        val device = this.device
        if (device == null || device.address == null) {
            return
        }

        binding.batteryView.postDelayed({
            val intent = Intent(BleCons.ACTION_REQUEST_BATTERY)
            intent.putExtra(BleCons.EXTRA_DEVICE_TYPE, SmartDevice.TYPE_HEART_RATE01)
            intent.putExtra(BleCons.EXTRA_DEVICE_ADDRESS, device.address)
            sendOrderedBroadcast(intent, null)
        }, 1600L)
    }

    fun requestDeviceInfo() {
        val device = this.device
        if (device == null || device.address == null) {
            return
        }
        val intent = Intent(BleCons.ACTION_REQUEST_DEVICE_INFORMATION)
        intent.putExtra(BleCons.EXTRA_DEVICE_TYPE, SmartDevice.TYPE_HEART_RATE01)
        intent.putExtra(BleCons.EXTRA_DEVICE_ADDRESS, device.address)
        sendOrderedBroadcast(intent, null)
    }

    private fun readDeviceInfo() {
        val device = this.device
        if (device == null || device.address == null) {
            return
        }

        binding.batteryView.postDelayed({
            if (device.address == null) {
                return@postDelayed
            }
            val intent = Intent(BleCons.ACTION_READ_DEVICE_INFORMATION)
            intent.putExtra(BleCons.EXTRA_DEVICE_TYPE, SmartDevice.TYPE_HEART_RATE01)
            intent.putExtra(BleCons.EXTRA_DEVICE_ADDRESS, device.address)
            sendOrderedBroadcast(intent, null)
        }, 1800L)
    }

    @SuppressLint("SetTextI18n")
    fun setUIBattery(battery: Int) {
        binding.batteryView.text = battery.toString() + Separators.PERCENT
    }

    fun setUIVersion(version: String?) {
        binding.versionName.text = version
        if (version != null) {
            checkVersion(version)
        }
    }

    fun setUIManufacture(manufacture: String?) {
        binding.manufactureName.text = manufacture
    }

    fun setUIModel(model: String?) {
        binding.modelName.text = model
    }

    override fun onDestroy() {
        unregisterReceiver(broadcastReceiver)
        DeviceHelper.unregisterConnectionStateListener(this)
        super.onDestroy()
    }

    private fun registerReceiver() {
        val intentFilter = IntentFilter()
        intentFilter.addAction(BleCons.ACTION_BATTERY)
        intentFilter.addAction(BleCons.ACTION_DEVICE_INFORMATION)
        intentFilter.addAction(BleCons.ACTION_CADENCE_DATAS)
        intentFilter.addAction(BleCons.ACTION_PRESSURE_DATAS)
        intentFilter.addAction(BleCons.ACTION_READ_DEVICE_INFORMATION_RESULT)
        intentFilter.addAction(HeartRate01Device.ACTION_DEVICE_MODE_INFO)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            registerReceiver(broadcastReceiver, intentFilter, Context.RECEIVER_EXPORTED);
        } else {
            registerReceiver(broadcastReceiver, intentFilter);
        }
    }

    @SuppressLint("SetTextI18n")
    override fun onRefreshUI(displayPoint: DisplayPoint) {
        val value = displayPoint.getHeartrate(0)
        if (value == 0) {
            binding.heartrateView.text = "--"
        } else {
            binding.heartrateView.text = value.toString()
        }

    }

    override fun onConnectionStateChanged(smartDevice: SmartDevice, i: Int, i2: Int) {
        if (smartDevice.type == SmartDevice.TYPE_HEART_RATE01 && device != null && smartDevice.address == device!!.address) {
            if (i == DeviceManager.STATE_CONNECTED) {
                requestMode()
                requestBattery()
                readDeviceInfo()
            } else if (i == DeviceManager.STATE_DISCONNECTED) {
                if (mDfuProgressDialog?.isShowing == true || !isShowFailToast) {
                    return
                }
                toast(R.string.mine_device_toast_connect_failed)
                finish()
            }
        }
    }

    private fun bindView() {
        binding.ibUpgradeFirmware.setOnClickListener { upgradeFirmware() }
//        binding.ibUpgradeFirmware.setVisibility(if (DeviceContext.getDeviceConfiguration().isDfuDebuggable) View.VISIBLE else View.GONE)
    }


    private fun upgradeFirmware() {
        AlertDialog.Builder(this).setMessage(
            getString(
                R.string.message_upgrade_fw_confirm, device!!.name
            )
        ).setPositiveButton(
            R.string.str_sync_confirm
        ) { _: DialogInterface?, _: Int ->

            onDfuProcessMessage(getString(R.string.message_upgrade_fw_starting))
            lifecycleScope.launch(Dispatchers.IO) {
                try {
                    getExternalFilesDir(null)?.let {
                        val path = it.absolutePath + "/" + Environment.DIRECTORY_DOWNLOADS
                        val file = File(path)
                        if (!file.exists()){
                            file.mkdirs();
                        }
                        dfuFilePath = path + "/" + "v" + System.currentTimeMillis() + ".zip"

                    }
                    FileDownloadUtils.downloadFile(downloadUrl,
                        dfuFilePath,
                        object : FileDownloadUtils.DownloadProgressListener {
                            override fun onProgress(progress: Int) {

                            }

                            override fun onComplete() {
                                runOnUiThread {
                                    if (!isFinishing) {
                                        startUpgrade()
                                    }
                                }

                            }

                            override fun onError(errorMessage: String?) {
                                runOnUiThread {
                                    if (!isFinishing) {
                                        dismissProgressDialog()
                                        toast(R.string.toast_download_failed)
                                    }
                                }
                            }
                        })
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
        }.setNegativeButton(R.string.cancel, null as DialogInterface.OnClickListener?).show()
    }

    private fun startUpgrade() {
        if (this.mDfuContext == null) {
            val device = this.device
            mDfuContext = DfuContext(
                this, device!!.address, device.name, device.type, dfuFilePath, true, this
            )
//            mDfuContext!!.isUseUri(true) //select ./ local file
        }
        mDfuContext!!.enterDfuMode()
    }


    public override fun onActivityResult(i: Int, i2: Int, intent: Intent?) {
        super.onActivityResult(i, i2, intent)
        val dfuContext = this.mDfuContext
        if (dfuContext != null) {
            try {
                dfuContext.parseDfuFile(i, i2, intent)
            } catch (e: Throwable) {
                throw RuntimeException(e)
            }
        }
    }


    private fun showProgressDialog(charSequence: CharSequence?) {
        val progressDialog = this.mDfuProgressDialog
        if (progressDialog == null) {
            val show = ProgressDialog(this, android.R.style.Theme_Material_Dialog)
            this.mDfuProgressDialog = show
            show.setCanceledOnTouchOutside(false)
            mDfuProgressDialog!!.setCancelable(false)
            return
        }
        progressDialog.setMessage(charSequence)
        mDfuProgressDialog!!.show()
    }

    private fun dismissProgressDialog() {
        val progressDialog = this.mDfuProgressDialog
        progressDialog?.dismiss()
    }

    override fun onDfuProcessMessage(str: String) {
        showProgressDialog(str)
    }

    override fun onProgressChanged(i: Int) {
        showProgressDialog(getString(R.string.message_upgrade_fw_in_progress, i))
    }

    override fun onUpgradeCompleted() {
        mDfuContext!!.setIncremental(false)
        dismissProgressDialog()
        XZDeviceHelper.setDeviceFwVersion(device?.address, "")
        DeviceContext.saveDeviceVersion(device!!.address, verName)
        AlertDialog.Builder(this).setMessage(R.string.message_upgrade_fw_on_success)
            .setPositiveButton(
                R.string.str_sync_confirm
            ) { _: DialogInterface?, i: Int -> finish() }.setCancelable(false).show()
            .setCanceledOnTouchOutside(false)
    }

    override fun onUpgradeFail(str: String) {
        dismissProgressDialog()
        AlertDialog.Builder(this).setMessage(R.string.message_upgrade_fw_fail).setPositiveButton(
            R.string.str_sync_confirm
        ) { _: DialogInterface?, i: Int ->
            try {
                startUpgrade()
            } catch (e: Throwable) {
                throw RuntimeException(e)
            }
        }.setNegativeButton(
            R.string.cancel
        ) { _: DialogInterface?, i: Int ->
            AlertDialog.Builder(this@HeartRate01StatusActivity)
                .setMessage(R.string.message_upgrade_fw_exit).setPositiveButton(
                    R.string.str_sync_confirm, null as DialogInterface.OnClickListener?
                ).setOnDismissListener { finish() }.show()
        }.setCancelable(false).show().setCanceledOnTouchOutside(false)
    }


    override fun onError(i: Int, i2: Int, str: String) {
        if (!isFinishing) {
            dismissProgressDialog()
            AlertDialog.Builder(this).setMessage(R.string.message_upgrade_fw_fail)
                .setPositiveButton(
                    R.string.str_sync_confirm
                ) { _: DialogInterface?, i: Int ->
                    try {
                        mDfuContext!!.setIncremental(true)
                        startUpgrade()
                    } catch (e: Throwable) {
                        throw RuntimeException(e)
                    }
                }.setCancelable(false).show().setCanceledOnTouchOutside(false)
        }
    }

    override fun onUpgradeStarted() {
    }

    companion object {
        private const val TAG = "HeartRate01StatusActivity"
    }

    private fun checkVersion(version: String?) {
        if (!isChecking && version != null && version.contains("v")) {
            try {
                isChecking = true
                val versionNumber = version.substring(version.indexOfLast { 'v' == it } + 1)
                MyHttpClient.getHeartRateVersion(object : BiCiCallback() {
                    override fun onResponseString(str: String) {
                        try {
                            isChecking = false
                            val jo = JSONObject(str)
                            val dataObject = jo.optJSONObject("data")
                            if (!isFinishing && dataObject != null) {
                                verName = "v" + dataObject.optString("verName")
                                downloadUrl = dataObject.optString("downloadUrl")
                                if (!downloadUrl.isNullOrEmpty()) {
                                    runOnUiThread { binding.ibUpgradeFirmware.setVisibility(View.VISIBLE) }
                                }
                            }
                        } catch (e: java.lang.Exception) {
                            e.printStackTrace()
                        }
                    }

                    override fun onResponseFail(str: String?) {
                        super.onResponseFail(str)
                        isChecking = false
                    }
                }, "heartrate01", versionNumber)
            } catch (e: Exception) {
                e.printStackTrace()
                isChecking = false
            }

        }

    }
}